#include "reactor/epoll.hpp"
#include "reactor/channel.hpp"
#include <sys/epoll.h>
#include <unistd.h>
#include <cassert>
#include <iostream>

namespace reactor {

Epoll::Epoll()
    : _epollfd(::epoll_create1(EPOLL_CLOEXEC)),
      _events(16) // 初始大小
{
    if (_epollfd < 0) {
        std::cerr << "epoll_create error" << std::endl;
        abort();
    }
}

Epoll::~Epoll() {
    ::close(_epollfd);
}

void Epoll::poll(std::vector<Channel*>& activeChannels) {
    int numEvents = ::epoll_wait(_epollfd, &*_events.begin(), static_cast<int>(_events.size()), -1);
    if (numEvents > 0) {
        for (int i = 0; i < numEvents; ++i) {
            Channel* channel = static_cast<Channel*>(_events[i].data.ptr);
            channel->setRevents(_events[i].events);
            activeChannels.push_back(channel);
        }
        if (static_cast<size_t>(numEvents) == _events.size()) {
            _events.resize(_events.size() * 2);
        }
    } else if (numEvents == 0) {
        // timeout, do nothing
    } else {
        if (errno != EINTR) {
            std::cerr << "Epoll::poll() error" << std::endl;
        }
    }
}

void Epoll::updateChannel(Channel* channel) {
    int fd = channel->fd();
    if (_channels.find(fd) == _channels.end()) {
        // Add
        _channels[fd] = channel;
        struct epoll_event ev;
        ev.data.ptr = channel;
        ev.events = channel->events();
        ::epoll_ctl(_epollfd, EPOLL_CTL_ADD, fd, &ev);
    } else {
        // Modify
        struct epoll_event ev;
        ev.data.ptr = channel;
        ev.events = channel->events();
        ::epoll_ctl(_epollfd, EPOLL_CTL_MOD, fd, &ev);
    }
}

void Epoll::removeChannel(Channel* channel) {
    int fd = channel->fd();
    _channels.erase(fd);
    ::epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd, nullptr);
}

} // namespace reactor
